package org.ubc.cs410.disposal2020.client.view;

import java.util.ArrayList;
import java.util.List;

import org.ubc.cs410.disposal2020.client.dto.BuildingBoundaryDto;

//import com.google.appengine.api.datastore.GeoPt;
import com.google.gwt.maps.client.MapOptions;
import com.google.gwt.maps.client.MapWidget;
import com.google.gwt.maps.client.event.MarkerDragEndHandler;
import com.google.gwt.maps.client.event.MarkerDragStartHandler;
import com.google.gwt.maps.client.event.MarkerDragEndHandler.MarkerDragEndEvent;
import com.google.gwt.maps.client.event.MarkerDragStartHandler.MarkerDragStartEvent;
import com.google.gwt.maps.client.geom.LatLng;
import com.google.gwt.maps.client.geom.Point;
import com.google.gwt.maps.client.overlay.Icon;
import com.google.gwt.maps.client.overlay.Marker;
import com.google.gwt.maps.client.overlay.MarkerOptions;
import com.google.gwt.maps.client.overlay.Overlay;
import com.google.gwt.maps.client.overlay.Polygon;
import com.google.gwt.user.client.ui.Composite;
import com.google.gwt.user.client.ui.VerticalPanel;

/*
 * Functions to add overlays, icons/markers on the map
 */

public class MapView extends Composite {

	private MapWidget map;

	private LatLng centerLocation;

	private int zoomLevel;

	private MapOptions mapOptions;

	private List<BuildingBoundaryDto> buildingBoundaryList;

	private MapView mapView = this;

	private LatLng startPt;
	private Polygon tempCircle;

	public MapView(LatLng centerLocation, int zoomLevel, MapOptions mapOption) {
		this.centerLocation = centerLocation;
		this.zoomLevel = zoomLevel;
		this.mapOptions = mapOption;

		this.buildingBoundaryList = new ArrayList<BuildingBoundaryDto>();
		initMap();
	}

	public void addOverlay(BuildingBoundaryDto buildingDto) {
		buildingBoundaryList.add(buildingDto);
		Polygon polygon = new Polygon(convertBuildingDtoToLatLng(buildingDto));
		getMap().addOverlay(polygon);
	}

	public void removeOverlay(BuildingBoundaryDto buildingDto) {
		buildingBoundaryList.remove(buildingDto);
		Polygon polygon = new Polygon(convertBuildingDtoToLatLng(buildingDto));
		getMap().removeOverlay(polygon);
	}

	public void clearAllOverylay() {
		buildingBoundaryList.clear();
		getMap().clearOverlays();
	}

	private LatLng[] convertBuildingDtoToLatLng(BuildingBoundaryDto buildingDto) {
		final int size = buildingDto.getLatitudes().size();

		// LatLng[] latLngArray = new LatLng[size];
		LatLng[] latLngArray = new LatLng[size + 1];

		for (int i = 0; i < size; i++) {
			double lat = buildingDto.getLatitudes().get(i);
			double log = buildingDto.getLongitudes().get(i);
			latLngArray[i] = LatLng.newInstance(lat, log);
		}

		// The change is to make the polygon layer closed instead of open
		latLngArray[size] = latLngArray[0];

		return latLngArray;
	}

	private void initMap() {
		setMap(new MapWidget(getCenterLocation(), getZoomLevel(),
				getMapOptions()));

		VerticalPanel loadMenu = new VerticalPanel();
		loadMenu.add(getMap());

		this.initWidget(loadMenu);

	}

	// function to add robots and garbage
	public Marker addIcon(LatLng latlng, String path) {
		return this.addIcon(latlng, path, false);
	}

	public Marker addIcon(LatLng latlng, String path, boolean draggable) {
		Icon icon = Icon.newInstance(path);
		icon.setIconAnchor(Point.newInstance(32, 64));
		MarkerOptions markerOptions = MarkerOptions.newInstance(icon);
		markerOptions.setDraggable(draggable);
		Marker marker = new Marker(latlng, markerOptions);
		getMap().addOverlay(marker);
		return marker;
	}

	// Override to allow for use of GeoPt
	/*
	 * public Marker addIcon(GeoPt gpt, String path, boolean draggable) { Icon
	 * icon = Icon.newInstance(path); icon.setIconAnchor(Point.newInstance(32,
	 * 64)); MarkerOptions markerOptions = MarkerOptions.newInstance(icon);
	 * markerOptions.setDraggable(draggable); LatLng ll =
	 * LatLng.newInstance(gpt.getLatitude(), gpt.getLongitude()); Marker marker
	 * = new Marker(ll, markerOptions); getMap().addOverlay(marker); return
	 * marker; }
	 */

	public Polygon addCircle(LatLng centre) {
		double radius = 0.1242742384;
		double points = 32;

		double d2r = Math.PI / 180; // degrees to radians
		double r2d = 180 / Math.PI; // radians to degrees
		double earthsradius = 3963; // 3963 is the radius of the earth in miles

		double rlat = (radius / earthsradius) * r2d;
		double rlng = rlat / Math.cos(centre.getLatitude() * d2r);

		ArrayList<LatLng> extp = new ArrayList<LatLng>();

		for (int i = 0; i < points + 1; i++) // one extra here makes sure we
			// connect
		{
			double theta = Math.PI * (i / (points / 2));
			double ex = centre.getLongitude() + (rlng * Math.cos(theta)); // center
			// a
			// +
			// radius
			// x
			// *
			// cos(theta)
			double ey = centre.getLatitude() + (rlat * Math.sin(theta)); // center
			// b
			// +
			// radius
			// y
			// *
			// sin(theta)
			extp.add(LatLng.newInstance(ey, ex));
		}

		LatLng[] latLngArray = new LatLng[extp.size()];

		for (int i = 0; i < extp.size(); i++) {
			double lat = extp.get(i).getLatitude();
			double log = extp.get(i).getLongitude();
			latLngArray[i] = LatLng.newInstance(lat, log);

		}

		Polygon polygon = new Polygon(latLngArray);
		getMap().addOverlay(polygon);

		return polygon;
	}

	/***************************
	 * setter and getter methods
	 ***************************/

	public int getZoomLevel() {
		return zoomLevel;
	}

	public MapWidget getMap() {
		return map;
	}

	public void setMap(MapWidget map) {
		this.map = map;
	}

	public LatLng getCenterLocation() {
		return centerLocation;
	}

	public void resetMapLocation(double latitude, double longitude,
			int zoomLevel) {
		LatLng latlng = LatLng.newInstance(latitude, longitude);
		setCenterLocation(latlng);
		setZoomLevel(zoomLevel);
		this.getMap().setCenter(getCenterLocation(), getZoomLevel());

	}

	public MapOptions getMapOptions() {
		return mapOptions;
	}

	public void setMapOptions(MapOptions mapOptions) {
		this.mapOptions = mapOptions;
	}

	public void setCenterLocation(LatLng centerLocation) {
		this.centerLocation = centerLocation;
	}

	public void setZoomLevel(int zoomLevel) {
		this.zoomLevel = zoomLevel;
	}


}
